{/* Copyright 2020 Adobe. All rights reserved.
This file is licensed to you under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. You may obtain a copy
of the License at http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under
the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
OF ANY KIND, either express or implied. See the License for the specific language
governing permissions and limitations under the License. */}

# Table Accessibility Specification

## Overview

A [`TableView`](https://react-spectrum.corp.adobe.com/components/TableView) displays a list of content with rows and columns.
It supports many advanced features like sorting, infinite scrolling, drag and drop both into and out of the table,
multiple selection, keyboard navigation, and more. It is designed to scale to collections of any size using a virtual scroller
that only renders the currently visible items into the DOM.

## WAI-ARIA Design Pattern

The [`TableView`](https://react-spectrum.corp.adobe.com/components/TableView) component implements the [Data Grid design pattern, per WAI-ARIA Authoring Practices 1.2](https://www.w3.org/TR/wai-aria-practices-1.2/#dataGrid).

A [`grid`](https://www.w3.org/TR/wai-aria-1.2/#grid) can be used to present tabular information that has column titles, row titles, or both.
The `grid` pattern is particularly useful if the tabular information is editable or interactive.
For example, when data elements are links to more information, rather than presenting them in a static table and including the links in the tab sequence,
implementing the `grid` pattern provides users with intuitive and efficient keyboard navigation of the `grid` contents as well as a shorter tab sequence for the page.
A `grid` may also offer functions, such as cell content editing, selection, cut, copy, and paste.

In a `grid`, every cell contains a focusable element or is itself focusable, regardless of whether the cell content is editable or interactive.
There is one exception: if column or row header cells do not provide functions, such as sort or filter, they do not need to be focusable.
One reason it is important for all cells to be able to receive or contain keyboard focus is that screen readers will typically be in their application reading mode, rather than their document reading mode, when users are interacting with the grid.
While in application mode, a screen reader user hears only focusable elements and content that labels focusable elements.
So, screen reader users may unknowingly overlook elements contained in a grid that are either not focusable or not used to label a column or row.

### Keyboard Interaction For Data Grids

The following keys provide grid navigation by moving focus among rows and cells of the grid.
Implementations of grid make these key commands available when an element in the grid has received focus, e.g., after a user has moved focus to the grid using the Tab key.

- `ArrowDown`
  - With focus on a row within the grid, moves focus to the next row within the grid.
  - With focus on a cell within a row, moves focus to the cell in the same column of the next row.
- `ArrowUp`
  - With focus on a row within the grid, moves focus to the previous row within the grid.
  - With focus on a cell within a row, moves focus to the cell in the same column of the previous row.
- `ArrowRight`
  - With focus on a row within the grid, moves focus to the first cell within the row.
  - With focus on or within a cell within a row, moves focus to the next cell within the row.
  - With focus on or within the right-most cell in the row, focus does not move.
- `ArrowLeft`
  - With focus on or within a cell within a row, moves focus to the previous cell within the row.
  - With focus on or within the left-most cell in the row, focus should move to the parent row.
  - With focus on a row within the grid, focus does not move.
- `PageDown`
  - Moves focus down a number of rows, typically scrolling so the bottom row in the currently visible set of rows becomes one of the first visible rows.
  - With focus on a cell within a row, focus should move to the cell in the same column of the row that receives focus after scrolling.
  - With focus on or within the last row of the grid, focus does not move.
- `PageUp`
  - Moves focus up a number of rows, typically scrolling so the top row in the currently visible set of rows becomes one of the last visible rows.
  - With focus on a cell within a row, focus should move to the cell in the same column of the row that receives focus after scrolling.
  - With focus on or within the first row of the grid, focus does not move.
- `Home`
  - With focus on a row within the grid, moves focus to the first row in the dataset for the grid, scrolling it into view.
  - With focus on a cell within a row, moves focus to the first cell in the row that contains focus.
- `End`
  - With focus on a row within the grid, moves focus to the last row in the dataset for the grid, scrolling it into view.
  - With focus on a cell within a row, moves focus to the last cell in the row that contains focus.
- `Control/Command + Home`
  - With focus on a row within the grid, moves focus to the first row in the dataset for the grid, scrolling it into view.
  - With focus on a cell within a row, moves focus to the first cell in the first row in the dataset for the grid, scrolling it into view.
- `Control/Command + End`
  - With focus on a row within the grid, moves focus to the last row in the dataset for the grid, scrolling it into view.
  - With focus on a cell within a row, moves focus to the last cell in the last row in the dataset for the grid, scrolling it into view.

When a row or any of its decendants has focus, any interactive control within the row, such as a link, checkbox, switch or button, should made tabbable using `tabIndex={0}`.
Interactive controls within rows that do not contain focus should be removed from the document tab order using `tabIndex={-1}`.

If a grid supports selection of rows, Spectrum does not currently support column or cell selection, the following keys are used for these functions:
- With focus on a row or cell,
  - `Space` toggles selection of the row.
  - `Shift + ArrowDown` extends selection one row down.
  - `Shift + ArrowUp` extends selection one row up.
  - `Shift + PageDown` extends selection one page down.
  - `Shift + PageUp` extends selection one page up.
  - `Control/Command + A`
    - selects all rows in the dataset.
    - (optional) depending on the size of the dataset, displays a dialog offering the user the option to select only visible rows, or all rows in the dataset.
  - `Escape` (optional) deselects all selected rows.
  - `Control/Command + C` (optional) depending on context, copies selected rows to the clipboard.
  - `Control/Command + V` (optional) depending on context, pastes rows from the clipboard into the table.

#### Keyboard Interaction - Setting Focus and Navigating Inside Cells

This section describes two important aspects of keyboard interaction design for data grid patterns:

1. Choosing whether a cell or an element inside a cell receives focus in response to grid navigation key events.
2. Enabling grid navigation keys to be used to interact with elements inside of a cell.

##### Whether to Focus on a Cell Or an Element Inside It

For assistive technology users, the quality of experience when navigating a grid heavily depends on both what a cell contains and on where keyboard focus is set. For example, if a cell contains a button and a grid navigation key places focus on the cell instead of the button, screen readers announce the button label but do not tell users a button is present.

There are two optimal cell design and focus behavior combinations:

1. A cell contains one widget whose operation does not require arrow keys and grid navigation keys set focus on that widget. Examples of such widgets include link, button, menubutton, toggle button, radio button (not radio group), switch, and checkbox.
2. A cell contains text or a single graphic and grid navigation keys set focus on the cell.

While any combination of widgets, text, and graphics may be included in a single cell, grids that do not follow one of these two cell design and focus movement patterns add complexity for authors or users or both.

##### Editing and Navigating Inside a Cell

While navigation keys, such as arrow keys, are moving focus from cell to cell, they are not available to perform actions like operate a combobox or move an editing caret inside of a cell. The user may need keys that are used for grid navigation to operate elements inside a cell if a cell contains:

1. Editable content.
2. Multiple widgets.
3. A widget that utilizes arrow keys in its interaction model, such as a radio group or slider.

Use the following keyboard conventions for disabling and restoring grid navigation functions.
- `Enter`: Disables grid navigation and:
  - If the cell contains editable content, places focus in an input field, such as a textbox. If the input is a single-line text field, a subsequent press of Enter may either restore grid navigation functions or move focus to an input field in a neighboring cell.
  - If the cell contains one or more widgets, places focus on the first widget.
- `Alphanumeric keys`: If the cell contains editable content, places focus in an input field, such as a textbox.

When grid navigation is disabled, conventional changes to navigation behaviors include:
- `Escape`: restores grid navigation. If content was being edited, it may also undo edits.
- `ArrowRight` or `ArrowDown`: If the cell contains multiple widgets, as with a radiogroup, moves focus to the next widget inside the cell, optionally wrapping to the first widget if focus is on the last widget. Otherwise, passes the key event to the focused widget.
- `ArrowLeft` or `ArrowUp`: If the cell contains multiple widgets, as with a radiogroup, moves focus to the previous widget inside the cell, optionally wrapping to the first widget if focus is on the last widget. Otherwise, passes the key event to the focused widget.
- `Tab`: moves focus to the next widget in the grid. Optionally, the focus movement may wrap inside a single cell or within the grid itself.
- `Shift + Tab`: moves focus to the previous widget in the grid. Optionally, the focus movement may wrap inside a single cell or within the grid itself.

### Roles, States, and Properties

- The table container has the role of [`grid`](https://www.w3.org/TR/wai-aria-1.2/#grid).
- Each row container has role of [`row`](https://www.w3.org/TR/wai-aria-1.2/#row) and is either a DOM descendant of or owned by the `grid` element or an element with role of [`rowgroup`](https://www.w3.org/TR/wai-aria-1.2/#rowgroup).
  - The header row or rows should be contained within an element with the role of [`rowgroup`](https://www.w3.org/TR/wai-aria-1.2/#rowgroup).
  - The scrolling table body element should be have the role of [`rowgroup`](https://www.w3.org/TR/wai-aria-1.2/#rowgroup).
  - Any other container element used to control layout, like for example the container elements that position item views within a virtual scroller, should have the role of [`presentation`](https://www.w3.org/TR/wai-aria-1.2/#presentation).
- Each cell is either a DOM descendant of, or owned by, a `row` element and has one of the following roles:
  - [`columnheader`](https://www.w3.org/TR/wai-aria-1.2/#columnheader) if the cell contains a title or header information for the column.
  - [`rowheader`](https://www.w3.org/TR/wai-aria-1.2/#rowheader) if the cell contains title or header information for the row.
  - [`gridcell`](https://www.w3.org/TR/wai-aria-1.2/#gridcell) if the cell does not contain column or row header information.
- If there is an element in the user interface that serves as a label for the `grid`, [`aria-labelledby`](https://www.w3.org/TR/wai-aria-1.2/#aria-labelledby) is set on the `grid` element with a value that refers to the labelling element. Otherwise, a label is specified for the `grid` element using [`aria-label`](https://www.w3.org/TR/wai-aria-1.2/#aria-label).
- If the grid has a description, [`aria-describedby`](https://www.w3.org/TR/wai-aria-1.2/#aria-describedby) is set on the grid element with a value referring to the element containing the description.
- If the grid provides sort functions, [`aria-sort`](https://www.w3.org/TR/wai-aria-1.2/#aria-sort) is set to an appropriate value on the header cell element for the sorted column or row as described in the section on [grid and table properties](https://www.w3.org/TR/wai-aria-practices-1.2/#gridAndTableProperties).
- Grid navigation using the arrow keys, page up/down, home or end focuses the `row` element. To improve announcement when it receives focus, each `row` should be labelled by column headers, and cells that best describe the `row` using [`aria-labelledby`](https://www.w3.org/TR/wai-aria-1.2/#aria-labelledby).
  - `TableView` should provide an API to specify which columns to include in the `aria-labelledby` for a row.
- If the grid supports selection, when a cell or row is selected, the selected element has [`aria-selected`](https://www.w3.org/TR/wai-aria-1.2/#aria-selected) set `true`.
  - The checkbox in the header row for selecting all items in the collection should have [`aria-label`](https://www.w3.org/TR/wai-aria-1.2/#aria-label) set to the localized string "Select All"."
  - The checkbox for selection of an item row should have [`aria-label`](https://www.w3.org/TR/wai-aria-1.2/#aria-label) set to a localized string that expresses the current selected state for the row, either "Selected" or "Select".
  - The checkbox in the first cell of an item row should also include an `aria-labelledby` prop that references the same columns used to label the parent `row` followed by the checkbox itself, to provide a clear indication of the selected state for the row.
  - When selected, the `aria-labelledby` attribute for the row should be updated to include a reference to the checkbox to ensure that the selected state for a `row` will be announced by a screen reader when the `row` receives focus.
- If the grid provides content editing functionality and contains cells that may have edit capabilities disabled in certain conditions, [`aria-readonly`](https://www.w3.org/TR/wai-aria-1.1/#aria-readonly) may be set `true` on cells where editing is disabled. If edit functions are disabled for all cells, `aria-readonly` may be set `true` on the `grid` element. Grids that do not provide editing functions do not include the `aria-readonly` attribute on any of their elements.
- If there are conditions where some rows or columns are hidden or not present in the DOM, e.g., data is dynamically loaded when scrolling or the grid provides functions for hiding rows or columns, the following properties are applied as described in the section on [grid and table properties](https://www.w3.org/TR/wai-aria-practices-1.2/#gridAndTableProperties).
  - [`aria-colcount`](https://www.w3.org/TR/wai-aria-1.2/#aria-colcount) or [`aria-rowcount`](https://www.w3.org/TR/wai-aria-1.2/#aria-rowcount) is set to the total number of columns or rows, respectively.
  - `aria-rowcount` or `aria-colcount` must update whenever items are added or removed from the dataset, or whenever a column is added or removed from the dataset.
  - [`aria-colindex`](https://www.w3.org/TR/wai-aria-1.2/#aria-colindex) or [`aria-rowindex`](https://www.w3.org/TR/wai-aria-1.2/#aria-rowindex) is set to the position of a cell within a row or column, respectively.
- If the grid includes cells that span multiple rows or multiple columns, and if the `grid` role is NOT applied to an HTML `table` element, then [`aria-rowspan`](https://www.w3.org/TR/wai-aria-1.2/#aria-rowspan) or [`aria-colspan`](https://www.w3.org/TR/wai-aria-1.2/#aria-colspan) is applied as described in [grid and table properties](https://www.w3.org/TR/wai-aria-practices-1.2/#gridAndTableProperties).

#### NOTE:

- If the element with the `grid` role is an HTML `table` element, then it is not necessary to use ARIA roles for rows and cells because the HTML elements have implied ARIA semantics. For example, an HTML `<TR>` has an implied ARIA role of `row`. A grid built from an HTML `table` that includes cells that span multiple rows or columns must use HTML `rowspan` and `colspan` and must not use `aria-rowspan` or `aria-colspan`.
- If rows or cells are included in a grid via `aria-owns`, they will be presented to assistive technologies after the DOM descendants of the `grid` element unless the DOM descendants are also included in the `aria-owns` attribute.

### Virtual scrolling

There are several important considerations when a table uses virtual scrolling to enable fast scrolling of large datasets.
- After scrolling, the order of visible item views in the DOM must match the order of item views in the dataset.
- While scrolling, if the `focusedKey` has scrolled out of view so that it is no longer rendered, focus should be set to the container element for the virtual scroller itself, so that focus is not lost to the `document.body` and the virtual scroller will continue to handle grid navigation keys.
- If the `focusedKey` is scrolled out of view, when the user navigates away from the grid, the grid should be made tabbable by setting `tabIndex={0}`. When keyboard navigation restores focus to the grid, the grid should marshall focus to the `focusedKey` and scroll the item into view.
- When navigating using a screen reader, using browse mode in particular, there is now way for force the loading of additional item views when the last, or first item, in the virtual scroller has been read. For this use case, it may become necessary to include a screen-reader only row, spanning all columns, before and after of the visible item views in the DOM that contain a button that allows a screen reader to load more items.
